#include	"a_global_vars.h"
#include	"config_parser.h"
#include	"str_parser.h"

//---------------------------------------STRUCTS--------------------------------------------------
struct server_info_t{
	
	node_id_t server_id;	
	char ip[16];
	int port;

	int self_sid;
	int successor_sid;
	
	int multicast_recv_sid;
	int multicast_send_sid;
	
	int learner_tcp_sid;
	int proposer_udp_id; // only for the multicast sender.
};
//-------------------------------------------------------------
struct proxy_info_t{
	
	node_id_t proxy_id;	
	char ip[16];
	int port;
	int proxy_sid;
		
};
//-------------------------------------------------------------
struct learner_acceptor_t{
	
	node_id_t	learner_id;
	node_id_t	acceptor_id;
	int 		acceptor_port;	
	
};
//-------------------------------------------------------------
struct config_info_t{
	
	node_id_t self_id;
	
	int total_num_acceptors;
	int total_num_proxies;
	int total_num_learners;
	
	char * multicast_ip; 
	int    multicast_port;
	
	server_info server_infos[MAX_SERVERS];
	proxy_info	proxy_infos[MAX_PROXIES];
	learner_acceptor learner_to_acceptor[MAX_LEARNERS];
	
	int proposer_to_multicaster_port;
};
//---------------------------------------VARIABLE DEFINISTIONS------------------------------------
config_info *config_info_sample = NULL;
//--------------------------------------------------------------------------------------------------------------------------
config_info * get_config_info(){
	return config_info_sample;
}
//-------------------------------------------------------------
void call_ip(const char * config_path, int process_id){
	char flag; 
	char *match;
	config_info_sample = malloc(sizeof(config_info));
	assert(config_info_sample != NULL);
	config_info_sample->self_id = (node_id_t)process_id;
	
	match = "acceptor";
	flag = 'a';
	get_ip_port(config_path, get_config_info(), match, flag);


	match = "proxy";
	flag = 'p';
	get_ip_port(config_path, get_config_info(), match, flag);


	match = "learner_to_acceptor";
	flag = 'l';
	get_ip_port(config_path, get_config_info(), match, flag);


	match = "multicast";
	char multicast_ip[STRING_SIZE];
	get_multicast_address(config_path, multicast_ip, match);
	config_info_sample->multicast_ip = multicast_ip;
	
	match = "proposer_to_multicaster";
	char proposer_multicaster_port[STRING_SIZE];
	get_multicast_address(config_path, proposer_multicaster_port, match);
	config_info_sample->proposer_to_multicaster_port = atoi(proposer_multicaster_port);
	
	create_sockets(config_info_sample);	
	form_ring(config_info_sample);
}
//-------------------------------------------------------------
void get_ip_port(const char* config_file, config_info * config, const char * match, char flag){
	
	FILE * fp;
	char  line[STRING_SIZE]; 
	char  word[STRING_SIZE];
	int  last_index = -1, server_counter = 0 ;

	fp = fopen(config_file, "r");
	while(!feof(fp)){
		if(fgets(line, STRING_SIZE, fp) != 0){
			last_index = get_substr(0, strlen(line) - 1, line, word);
			
			if(strcmp(word, match) == 0){

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if(flag == 'a')
					config->server_infos[server_counter].server_id = (node_id_t)atoi(word);
				else if(flag == 'p')
					config->proxy_infos[server_counter].proxy_id = (node_id_t)atoi(word);
				else if(flag == 'l')	
					config->learner_to_acceptor[server_counter].learner_id = (node_id_t)atoi(word);

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if(flag == 'a')
					memcpy(config->server_infos[server_counter].ip , word, strlen(word));
				else if(flag == 'p')
					memcpy(config->proxy_infos[server_counter].ip , word, strlen(word));
				else if(flag == 'l')	
					config->learner_to_acceptor[server_counter].acceptor_id = (node_id_t)atoi(word);
					

				last_index = get_substr(last_index + 1, strlen(line) - 1, line, word);
				if(flag == 'a')
					config->server_infos[server_counter].port = atoi(word);
				else if (flag == 'p')
					config->proxy_infos[server_counter].port = atoi(word);
				else if(flag == 'l')	
					config->learner_to_acceptor[server_counter].acceptor_port = atoi(word);

				server_counter ++;
			}
		}
	}
	if(flag == 'a')
		config->total_num_acceptors = server_counter;
	else if(flag == 'p')
		config->total_num_proxies = server_counter;
	else if(flag == 'l')	
		config->total_num_learners = server_counter;
}
//-------------------------------------------------------------
void get_multicast_address(const char* config_file, char *ip, const char * match){
	
	FILE * fp;
	char  line[STRING_SIZE], word[STRING_SIZE];
	int  last_index = -1;

	fp = fopen(config_file, "r");
	while(!feof(fp)){
		if(fgets(line, STRING_SIZE, fp) != 0){
			last_index = get_substr(0, strlen(line) - 1, line, word);
			if(strcmp(word, match) == 0)
				last_index = get_substr(last_index + 1, strlen(line) - 1, line, ip);
		}
	}
}
//-------------------------------------------------------------
void form_ring(config_info *config){
	
	if(config->server_infos[config->self_id].self_sid != config->total_num_acceptors - 1){
		config->server_infos[config->self_id].self_sid = UDP_server(config->server_infos[config->self_id].ip, config->server_infos[config->self_id].port);
		config->server_infos[config->self_id].successor_sid = UDP_client(config->server_infos[config->self_id + 1].ip, config->server_infos[config->self_id + 1].port);
	}
	else{
		config->server_infos[config->self_id].self_sid = UDP_server(config->server_infos[config->self_id].ip, config->server_infos[config->self_id].port);
		config->server_infos[config->self_id].successor_sid = UDP_client(config->server_infos[0].ip, config->server_infos[0].port);
	}
	
}
//-------------------------------------------------------------
void create_sockets(config_info *config){
	if(config->self_id == 0){
		config->server_infos[config->self_id].multicast_send_sid = create_ip_multicast_sender_socket(config->multicast_ip);
	}
	else{
		config->server_infos[config->self_id].multicast_recv_sid = create_ip_multicast_receiver_socket(config->multicast_port, config->multicast_ip, config->server_infos[config->self_id].ip);
	}
}
//--------getters------------
int GET_SELF_SID(){
	return config_info_sample->server_infos[config_info_sample->self_id].self_sid;
}
int GET_SUCCESSOR_SID(){
	return config_info_sample->server_infos[config_info_sample->self_id].successor_sid;
}
int GET_SID_FOR_PROPOSER(){
	return config_info_sample->server_infos[config_info_sample->self_id].proposer_udp_id;	
}
int GET_SID_FOR_LEARNER(){
	return config_info_sample->server_infos[config_info_sample->self_id].learner_tcp_sid;	
}
int GET_SID_FOR_MULTICAST_RECV(){
	return config_info_sample->server_infos[config_info_sample->self_id].multicast_recv_sid;	
}
int GET_SID_FOR_MULTICAST_SEND(){
	return config_info_sample->server_infos[config_info_sample->self_id].multicast_send_sid;
}
struct sockaddr_in GET_MULTICAST_SOCKADDR(){
	return getAddr(config_info_sample->multicast_port, config_info_sample->multicast_ip);
}
